﻿using System.Collections.Generic;
using System.Linq;

using VirtualTournaments.Business.Tournaments;
using VirtualTournaments.DataAccess.SqlServer.DataProxies;
using VirtualTournaments.DataAccess.SqlServer.Exceptions;

namespace VirtualTournaments.DataAccess.SqlServer.DataMappers
{
	internal sealed class AllAgainstAllTournamentsDataMapper : AbstractDataMapper<SqlServer.Tournament, Business.Tournaments.AllAgainstAllTournament, DataProxies.AllAgainstAllTournamentDataProxy>
	{
		#region Singleton implementation

		private static AllAgainstAllTournamentsDataMapper _instance = null;
		private static object _instanceLocker = new object();

		private AllAgainstAllTournamentsDataMapper() { }

		public static AllAgainstAllTournamentsDataMapper Instance
		{
			get
			{
				if (_instance == null)
				{
					lock (_instanceLocker)
					{
						if (_instance == null)
						{
							_instance = new AllAgainstAllTournamentsDataMapper();
						}
					}
				}
				return _instance;
			}
		}

		#endregion

		internal override VirtualTournamentsDataContext GetDataContext()
		{
			return VirtualTournamentsDataContext.Instance;
		}

		internal override System.Data.Linq.Table<SqlServer.Tournament> GetDataTable()
		{
			return GetDataContext().Tournaments;
		}

		internal override Business.Tournaments.AllAgainstAllTournament DataObject2BusinessObject(SqlServer.Tournament dataObject)
		{
			List<Business.Tournaments.Team> teams = new List<Business.Tournaments.Team>();
			foreach (SqlServer.TournamentTeam tournamentTeam in dataObject.TournamentTeams)
			{
				teams.Add(TeamsDataMapper.Instance.DataObject2BusinessObject(tournamentTeam.Team));
			}

			switch ((TournamentKind)dataObject.Kind)
			{
				case TournamentKind.AllAgainstAllTournament:
					return new AllAgainstAllTournamentDataProxy(dataObject, teams);
				case TournamentKind.PlayOffTournament:
					throw new System.NotImplementedException();
			}
			throw new DataProxyNotFound();
		}

		internal override void BusinessObject2DataObject(Business.Tournaments.AllAgainstAllTournament bizTournament, SqlServer.Tournament dataTournament)
		{
			dataTournament.Kind = (int)TournamentKind.AllAgainstAllTournament;
			dataTournament.Name = bizTournament.Name;
			dataTournament.IsFinished = bizTournament.IsFinished;
			dataTournament.IsActive = bizTournament.IsActive;
			if (bizTournament.First != null)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTournament.First.Name);
				if (dataTeam != null)
					dataTournament.FirstTeam = dataTeam;
				else
					dataTournament.FirstTeam = TeamsDataMapper.Instance.Save(bizTournament.First);
			}
			if (bizTournament.Second != null)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTournament.Second.Name);
				if (dataTeam != null)
					dataTournament.SecondTeam = dataTeam;
				else
					dataTournament.SecondTeam = TeamsDataMapper.Instance.Save(bizTournament.Second);
			}
			if (bizTournament.Third != null)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTournament.Third.Name);
				if (dataTeam != null)
					dataTournament.ThirdTeam = dataTeam;
				else
					dataTournament.ThirdTeam = TeamsDataMapper.Instance.Save(bizTournament.Third);
			}
			dataTournament.CurrentJourneyNumber = bizTournament.LastJourneyNumber;
			dataTournament.Journeys.Clear();
			if (bizTournament.Fixture != null && bizTournament.Fixture.Count() > 0)
			{
				int journeyNumber = 0;
				foreach (Business.Tournaments.Journey bizJourney in bizTournament.Fixture)
				{
					SqlServer.Journey dataJourney = JourneysDataMapper.Instance.GetOneAsDataObject(journey => journey.Tournament.Name == bizTournament.Name && journey.Number == bizJourney.Number);
					if (dataJourney == null)
						dataJourney = new SqlServer.Journey();
					dataJourney.Number = ++journeyNumber;
					dataTournament.Journeys.Add(dataJourney);

					dataJourney.JourneyMatches.Clear();
					foreach (Business.Tournaments.Match bizMatch in bizJourney)
					{
						SqlServer.JourneyMatch dataJourneyMatch = GetDataContext().JourneyMatches.Where(journeyMatches => journeyMatches.Journey.Tournament.Name == bizTournament.Name && journeyMatches.Match.LocalTeam.Name == bizMatch.Local.Name && journeyMatches.Match.VisitorTeam.Name == bizMatch.Visitor.Name).FirstOrDefault();
						if (dataJourneyMatch == null)
							dataJourneyMatch = new SqlServer.JourneyMatch();
						dataJourneyMatch.Match = MatchesDataMapper.Instance.Save(bizMatch);
						dataJourney.JourneyMatches.Add(dataJourneyMatch);
					}
				}
			}
			dataTournament.TournamentTeams.Clear();
			if (bizTournament.Teams != null && bizTournament.Teams.Count() > 0)
			{
				foreach (Business.Tournaments.Team bizTeam in bizTournament.Teams)
				{
					SqlServer.TournamentTeam dataTournamentTeam = new SqlServer.TournamentTeam();
					SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTeam.Name);
					if (dataTeam != null)
						dataTournamentTeam.TeamId = dataTeam.TeamId;
					else
						dataTournamentTeam.Team = TeamsDataMapper.Instance.Save(bizTeam);
					dataTournament.TournamentTeams.Add(dataTournamentTeam);
				}
			}
			dataTournament.Standings.Clear();
			if (bizTournament.Standings != null && bizTournament.Standings.Count() > 0)
			{
				foreach (Business.Tournaments.TeamStatics bizTeamStatics in bizTournament.Standings)
				{
					SqlServer.Standing dataStanding = GetDataContext().Standings.Where(standings => standings.Tournament.Name == bizTournament.Name && standings.Team.Name == bizTeamStatics.Team.Name).FirstOrDefault();
					if (dataStanding == null)
						dataStanding = new SqlServer.Standing();
					SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTeamStatics.Team.Name);
					if (dataTeam == null)
						dataTeam = GetDataContext().Teams.Where(team => team.Name == bizTeamStatics.Team.Name).FirstOrDefault();
					if (dataTeam != null)
						dataStanding.TeamId = dataTeam.TeamId;
					else
						dataStanding.Team = TeamsDataMapper.Instance.Save(bizTeamStatics.Team);
					dataStanding.Points = bizTeamStatics.Points;
					dataStanding.GoalsFor = bizTeamStatics.GoalsFor;
					dataStanding.GoalsAgainst = bizTeamStatics.GoalsAgainst;
					dataStanding.GoalsDifference = bizTeamStatics.GoalsDifference;
					dataStanding.PlayedMatches = bizTeamStatics.PlayedMatches;
					dataStanding.WonMatches = bizTeamStatics.WonMatches;
					dataStanding.DrawMatches = bizTeamStatics.DrawMatches;
					dataStanding.LostMatches = bizTeamStatics.LostMatches;
					dataTournament.Standings.Add(dataStanding);
				}
			}
		}

		internal override void DataProxy2DataObject(AllAgainstAllTournamentDataProxy proxyTournament, SqlServer.Tournament dataTournament)
		{
			dataTournament.Name = proxyTournament.Name;
			dataTournament.IsFinished = proxyTournament.IsFinished;
			dataTournament.IsActive = proxyTournament.IsActive;
			if (proxyTournament.FirstHasBeenRead)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == proxyTournament.First.Name);
				if (dataTeam != null)
					dataTournament.FirstTeamId = dataTeam.TeamId;
				else
					dataTournament.FirstTeam = TeamsDataMapper.Instance.Save(proxyTournament.First);
			}
			if (proxyTournament.SecondHasBeenRead)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == proxyTournament.Second.Name);
				if (dataTeam != null)
					dataTournament.SecondTeamId = dataTeam.TeamId;
				else
					dataTournament.SecondTeam = TeamsDataMapper.Instance.Save(proxyTournament.Second);
			}
			if (proxyTournament.ThirdHasBeenRead)
			{
				SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == proxyTournament.Third.Name);
				if (dataTeam != null)
					dataTournament.ThirdTeamId = dataTeam.TeamId;
				else
					dataTournament.ThirdTeam = TeamsDataMapper.Instance.Save(proxyTournament.Third);
			}
			dataTournament.CurrentJourneyNumber = proxyTournament.LastJourneyNumber;
			if (proxyTournament.FixtureHasBeenRead && ((FixtureDataProxy)proxyTournament.Fixture).JourneysHasBeenRead)
			{
				dataTournament.Journeys.Clear();
				((FixtureDataProxy)proxyTournament.Fixture).InternalJourneys.ForEach
				(
					journey => dataTournament.Journeys.Add(JourneysDataMapper.Instance.BusinessObject2DataObject(journey))
				);
			}
			if (proxyTournament.TeamsHasBeenRead)
			{
				dataTournament.TournamentTeams.Clear();
				proxyTournament.Teams.ForEach
				(
					team => dataTournament.TournamentTeams.Add
					(
						new SqlServer.TournamentTeam()
						{
							Team = TeamsDataMapper.Instance.BusinessObject2DataObject(team),
							Tournament = dataTournament,
						}
					)
				);
			}
			if (proxyTournament.StandingsHasBeenRead)
			{
				dataTournament.Standings.Clear();
				foreach (Business.Tournaments.TeamStatics bizTeamStatics in proxyTournament.Standings)
				{
					SqlServer.Standing dataStanding = new SqlServer.Standing();
					SqlServer.Team dataTeam = TeamsDataMapper.Instance.GetOneAsDataObject(team => team.Name == bizTeamStatics.Team.Name);
					if (dataTeam != null)
						dataStanding.TeamId = dataTeam.TeamId;
					else
						dataStanding.Team = TeamsDataMapper.Instance.Save(bizTeamStatics.Team);
					dataStanding.Points = bizTeamStatics.Points;
					dataStanding.GoalsFor = bizTeamStatics.GoalsFor;
					dataStanding.GoalsAgainst = bizTeamStatics.GoalsAgainst;
					dataStanding.GoalsDifference = bizTeamStatics.GoalsDifference;
					dataStanding.PlayedMatches = bizTeamStatics.PlayedMatches;
					dataStanding.WonMatches = bizTeamStatics.WonMatches;
					dataStanding.DrawMatches = bizTeamStatics.DrawMatches;
					dataStanding.LostMatches = bizTeamStatics.LostMatches;
					dataTournament.Standings.Add(dataStanding);
				}
			}
		}
	}
}
